#!/usr/bin/env python
# encoding: utf-8
# author: 04

import logging

from main.common.absolute_timer import AbsoluteTimer
from main.common.redis.redis_cli import RedisClient


class BaseService(object):
    """
    守护进程基础类，守护方式由supervisor保持，此处管理运行实现
    self.conflict_key: 如果希望此进程单例运行，需要定义 conflict_key 用于加锁
    self.loop_step: 每次运行间隔，默认60秒
    self.lock_multi_duration  默认锁时长对比 loop_step 的乘数，延长此乘数避免程序运行时间过长
    提供 self.loop_times 计算循环次数
    """

    loop_step = 5
    conflict_key = None
    lock_multi_duration = 2
    _timer = None

    def __init__(self):
        self.logger = logging.getLogger('deamon_task')
        self.loop_times = 0
        if self.conflict_key:
            self.lock = RedisClient.lock(
                name=f'service_conflict_lock:{self.conflict_key}',
                timeout=self.loop_step * self.lock_multi_duration
            )
        else:
            self.lock = None

    @property
    def timer(self):
        """ lazy make a timer """
        if not self._timer:
            self._timer = AbsoluteTimer(self.loop_step)
        return self._timer

    def run(self):
        """
        由于lock会持续不断请求redis，采用非阻塞方式, 每 loop_step 才请求一次
        如未设置conflict_key，则任意进程均会执行
        loop_times 增加时机：task执行之后，sleep之前
        """
        while True:
            if self.lock:
                locked = self.lock.acquire(blocking=False)
            else:
                locked = True
            if locked:
                try:
                    self.task()
                except Exception as e:
                    self.logger.exception(e)
            self.loop_times += 1
            try:
                self.timer.sleep()
            finally:
                # 防止sleep时中断进程导致报错
                if self.lock and self.lock.locked():
                    self.lock.release()
